home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / hop.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  8.8 KB  |  368 lines

  1. /*
  2.  *    HOP.C   -- trace route packets take to a remote host
  3.  *
  4.  *    02-90    -- Katie Stevens (dkstevens@ucdavis.edu)
  5.  *           UC Davis, Computing Services
  6.  *           Davis, CA
  7.  *    04-90    -- Modified by Phil Karn to use raw IP sockets to read replies
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "usock.h"
  15. #include "socket.h"
  16. #include "session.h"
  17. #include "timer.h"
  18. #include "proc.h"
  19. #include "netuser.h"
  20. #include "commands.h"
  21. #include "tty.h"
  22. #include "cmdparse.h"
  23. #include "ip.h"
  24. #include "icmp.h"
  25. #include "udp.h"
  26.  
  27. #define HOPMAXQUERY    5        /* Max# queries each TTL value */
  28. static int16 Hoprport = 32768+666;    /* funny port for udp probes */
  29. #define HOP_HIGHBIT    32768        /* Mask to check ICMP msgs */
  30.  
  31.  
  32. #define HOPTRACE    1        /* Enable HOP tracing */
  33. #ifdef HOPTRACE
  34. static int Hoptrace = 0;
  35. static int hoptrace __ARGS((int argc,char *argv[],void *p));
  36. #endif
  37.  
  38.  
  39. static unsigned  short Hopmaxttl  = 30;        /* max attempts */
  40. static unsigned  short Hopmaxwait = 5;        /* secs timeout each attempt */
  41. static unsigned  short Hopquery   = 3;        /* #probes each attempt */
  42.  
  43. static int hopcheck __ARGS((int argc,char *argv[],void *p));
  44. static int hopttl __ARGS((int argc,char *argv[],void *p));
  45. static int hopwait __ARGS((int argc,char *argv[],void *p));
  46. static int hopnum __ARGS((int argc,char *argv[],void *p));
  47. static int geticmp __ARGS((int s,int32 *sender,char *type,char *code));
  48.  
  49. static struct cmds Hopcmds[] = {
  50.     "check",    hopcheck,    2048,    2,    "check <host>",
  51.     "maxttl",    hopttl,        0,    0,    NULLCHAR,
  52.     "maxwait",    hopwait,    0,    0,    NULLCHAR,
  53.     "queries",    hopnum,        0,    0,    NULLCHAR,
  54. #ifdef HOPTRACE
  55.     "trace",    hoptrace,    0,    0,    NULLCHAR,
  56. #endif
  57.     NULLCHAR,
  58. };
  59.  
  60. /****************************************************************************/
  61.  
  62. /* attempt to trace route to a remote host */
  63. int
  64. dohop(argc,argv,p)
  65. int argc;
  66. char *argv[];
  67. void *p;
  68. {
  69.     return subcmd(Hopcmds,argc,argv,p);
  70. }
  71.  
  72. /****************************************************************************/
  73.  
  74. /* Set/show # queries sent each TTL value */
  75. static int
  76. hopnum(argc,argv,p)
  77. int argc;
  78. char *argv[];
  79. void *p;
  80. {
  81.     int16 r;
  82.     int16 x = Hopquery;
  83.     r = setshort(&x,"# queries each attempt",argc,argv);
  84.     if ((x <= 0)||(x > HOPMAXQUERY)) {
  85.         printf("Must be  0 < x <= %d\n",HOPMAXQUERY);
  86.         return 0;
  87.     } else {
  88.         Hopquery = x;
  89.     }
  90.     return (int)r;
  91. }
  92. #ifdef HOPTRACE
  93. /* Set/show tracelevel */
  94. static int
  95. hoptrace(argc,argv,p)
  96. int argc;
  97. char *argv[];
  98. void *p;
  99. {
  100.     return setbool(&Hoptrace,"HOPCHECK tracing",argc,argv);
  101. }
  102. #endif
  103. /* Set/show maximum TTL value for a traceroute query */
  104. static int
  105. hopttl(argc,argv,p)
  106. int argc;
  107. char *argv[];
  108. void *p;
  109. {
  110.     int16 r;
  111.     int16 x = Hopmaxttl;
  112.     r = setshort(&x,"Max attempts to reach host",argc,argv);
  113.     if ((x <= 0)||(x > 255)) {
  114.         printf("Must be  0 < x <= 255\n");
  115.         return 0;
  116.     } else {
  117.         Hopmaxttl = x;
  118.     }
  119.     return (int)r;
  120. }
  121. /* Set/show #secs until timeout for a traceroute query */
  122. static int
  123. hopwait(argc,argv,p)
  124. int argc;
  125. char *argv[];
  126. void *p;
  127. {
  128.     int16 r;
  129.     int16 x = Hopmaxwait;
  130.     r = setshort(&x,"# secs to wait for reply to query",argc,argv);
  131.     if (x <= 0) {
  132.         printf("Must be >= 0\n");
  133.         return 0;
  134.     } else {
  135.         Hopmaxwait = x;
  136.     }
  137.     return (int)r;
  138. }
  139.  
  140. /****************************************************************************/
  141.  
  142. /* send probes to trace route of a remote host */
  143. static int
  144. hopcheck(argc,argv,p)
  145. int argc;
  146. char *argv[];
  147. void *p;
  148. {
  149.     struct session *sp;        /* Session for trace output */
  150.     int s;                /* Socket for queries */
  151.     int s1;                /* Raw socket for replies */
  152.     struct socket lsocket;        /* Local socket sending queries */
  153.     struct socket rsocket;        /* Final destination of queries */
  154.     int32 cticks[HOPMAXQUERY];    /* Timers for query replies */
  155.     int32 icsource;            /* Sender of last ICMP reply */
  156.     char ictype;            /* ICMP type last ICMP reply */
  157.     char iccode;            /* ICMP code last ICMP reply */
  158.     int32 lastaddr;            /* Sender of previous ICMP reply */
  159.     struct sockaddr_in sock;
  160.     register struct usock *usp;
  161.     register struct sockaddr_in *sinp;
  162.     unsigned char sndttl, q;
  163.     int tracedone = 0;
  164.  
  165.     /* Allocate a session descriptor */
  166.     if((sp = newsession(argv[1],HOP)) == NULLSESSION){
  167.         tprintf("Too many sessions\n");
  168.         freeargs(argc,argv);
  169.         keywait(NULLCHAR,1);
  170.         return 1;
  171.     }
  172.     sp->s = s = -1;
  173.     sp->flowmode = 1;
  174.  
  175.     /* Setup UDP socket to remote host */
  176.     sock.sin_family = AF_INET;
  177.     sock.sin_port = Hoprport;
  178.     tprintf("Resolving %s... ",argv[1]);
  179.     if((sock.sin_addr.s_addr = resolve(argv[1])) == 0){
  180.         tprintf(Badhost,argv[1]);
  181.         freeargs(argc,argv);
  182.         keywait(NULLCHAR,1);
  183.         freesession(sp);
  184.         return 1;
  185.     }
  186.     freeargs(argc,argv);
  187.  
  188.     /* Open socket to remote host */
  189.     tprintf("traceroute to %s\n",psocket((struct sockaddr *)&sock));
  190.     if((sp->s = s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  191.         tprintf("Can't create udp socket\n");
  192.         keywait(NULLCHAR,1);
  193.         freesession(sp);
  194.         return 1;
  195.     }
  196.     if(connect(s,(char *)&sock,sizeof(sock)) == -1){
  197.         tprintf("Connect failed\n");
  198.         keywait(NULLCHAR,1);
  199.         freesession(sp);
  200.         return 1;
  201.     }
  202.     if((s1 = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  203.         tprintf("Can't create raw socket\n");
  204.         keywait(NULLCHAR,1);
  205.         freesession(sp);
  206.         return 1;
  207.     }
  208.     /* Setup structures to send queries */
  209.     /* Retrieve socket details for user socket control block */
  210.     usp = itop(s);
  211.     sinp = (struct sockaddr_in *)usp->name;
  212.     lsocket.address = sinp->sin_addr.s_addr;
  213.     lsocket.port = sinp->sin_port;
  214.     sinp = (struct sockaddr_in *)usp->peername;
  215.     rsocket.address = sinp->sin_addr.s_addr;
  216.  
  217.     /* Send queries with increasing TTL; start with TTL=1 */
  218.     if (Hoptrace)
  219.         mainlog(sp->s,"HOPCHECK start trace to %s\n",sp->name);
  220.     for (sndttl=1; (sndttl < Hopmaxttl); ++sndttl, sinp->sin_port++) {
  221.         /* Increment funny UDP port number each round */
  222.         rsocket.port = sinp->sin_port;
  223.         tprintf("%2d: ",sndttl);
  224.         lastaddr = (int32)0;
  225.         /* Send a round of queries */
  226.         for (q=0; (q < Hopquery); ++q) {
  227.             send_udp(&lsocket,&rsocket,0,sndttl,NULLBUF,0,0,0);
  228.             cticks[q] = Clock;
  229.         }
  230.         alarm( ((long)Hopmaxwait*1000/MSPTICK) );
  231.         for (q=0; q<Hopquery; ++q) {
  232.             /* Wait for a reply to our query */
  233.             if(geticmp(s1,&icsource,&ictype,&iccode) == -1){
  234.                 if(errno != EALARM)
  235.                     goto done;    /* User reset */
  236.                 /* Alarm rang, give up waiting for replies */
  237.                 tprintf("   ***");
  238.                 break;
  239.             }
  240.             /* Save #ticks taken for reply */
  241.             cticks[q] = (Clock - cticks[q]);
  242.             /* Report ICMP reply */
  243.             if (icsource != lastaddr) {
  244.                 tprintf("%s",inet_ntoa(icsource));
  245.                 lastaddr = icsource;
  246.             }
  247.             tprintf("   (%ld ms)",(cticks[q]*MSPTICK));
  248. #ifdef HOPTRACE
  249.             if (Hoptrace)
  250.                 mainlog(sp->s,"(hopcheck) ICMP from %s (%ldms) %s %s",
  251.                     inet_ntoa(icsource),
  252.                     (cticks[q]*MSPTICK),
  253.                     Icmptypes[ictype],
  254.                     ((ictype == ICMP_TIME_EXCEED)?Exceed[iccode]:Unreach[iccode]));
  255. #endif
  256.  
  257.             /* Check type of reply */
  258.             if (ictype == ICMP_TIME_EXCEED)
  259.                 continue;
  260.             /* Reply was: destination unreachable */
  261.             switch(iccode) {
  262.             case ICMP_PORT_UNREACH:
  263.                 ++tracedone;
  264.                 break;
  265.             case ICMP_NET_UNREACH:
  266.                 ++tracedone;
  267.                 tprintf(" !N");
  268.                 break;
  269.             case ICMP_HOST_UNREACH:
  270.                 ++tracedone;
  271.                 tprintf(" !H");
  272.                 break;
  273.             case ICMP_PROT_UNREACH:
  274.                 ++tracedone;
  275.                 tprintf(" !P");
  276.                 break;
  277.             case ICMP_FRAG_NEEDED:
  278.                 ++tracedone;
  279.                 tprintf(" !F");
  280.                 break;
  281.             case ICMP_ROUTE_FAIL:
  282.                 ++tracedone;
  283.                 tprintf(" !S");
  284.                 break;
  285.             }
  286.         }
  287.         /* Done with this round of queries */
  288.         alarm((long)0);
  289.         tprintf("\n");
  290.         /* Check if we reached remote host this round */
  291.         if (tracedone != 0)
  292.             break;
  293.     }
  294.  
  295.     /* Done with traceroute */
  296. done:    close_s(s);
  297.     sp->s = -1;
  298.     close_s(s1);
  299.     tprintf("traceroute done: ");
  300.     if (sndttl >= Hopmaxttl) {
  301.         tprintf("!! maximum TTL exceeded\n");
  302.     } else if ((icsource == rsocket.address)
  303.             &&(iccode == ICMP_PORT_UNREACH)) {
  304.         tprintf("normal (%s %s)\n",
  305.             Icmptypes[ictype],Unreach[iccode]);
  306.     } else {
  307.         tprintf("!! %s %s\n",
  308.             Icmptypes[ictype],Unreach[iccode]);
  309.     }
  310. #ifdef HOPTRACE
  311.     if (Hoptrace)
  312.         mainlog(sp->s,"HOPCHECK to %s done",sp->name);
  313. #endif
  314.     keywait(NULLCHAR,1);
  315.     freesession(sp);
  316.     return 0;
  317. }
  318.  
  319. /* Read raw network socket looking for ICMP messages in response to our
  320.  * UDP probes
  321.  */
  322. static int
  323. geticmp(s,sender,type,code)
  324. int s;
  325. int32 *sender;
  326. char *type,*code;
  327. {
  328.     int size;
  329.     struct icmp icmphdr;
  330.     struct ip iphdr;
  331.     struct udp udphdr;
  332.     struct mbuf *bp;
  333.     struct sockaddr_in sock;
  334.  
  335.     for(;;){
  336.         size = sizeof(sock);
  337.         if(recv_mbuf(s,&bp,0,(char *)&sock,&size) == -1)
  338.             return -1;
  339.         /* It's an ICMP message, let's see if it's interesting */
  340.         ntohicmp(&icmphdr,&bp);
  341.         if((icmphdr.type != ICMP_TIME_EXCEED ||
  342.          icmphdr.code != ICMP_TTL_EXCEED)
  343.          && icmphdr.type != ICMP_DEST_UNREACH){
  344.             /* We're not interested in these */
  345.             free_p(bp);
  346.             continue;
  347.         }
  348.         ntohip(&iphdr,&bp);
  349.         if(iphdr.protocol != UDP_PTCL){
  350.             /* Not UDP, so can't be interesting */
  351.             free_p(bp);
  352.             continue;
  353.         }
  354.         ntohudp(&udphdr,&bp);
  355.         if((udphdr.dest & HOP_HIGHBIT) == 0){
  356.             /* Not to a hopcheck port */
  357.             free_p(bp);
  358.             continue;
  359.         }
  360.         /* Passed all of our checks, so return it */
  361.         *sender = sock.sin_addr.s_addr;
  362.         *type = icmphdr.type;
  363.         *code = icmphdr.code;
  364.         free_p(bp);
  365.         return 0;
  366.     }
  367. }
  368.